using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Snake_DELALANDE_PELLEGRINI
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Texture2D background;

        Texture2D teteSerpent, teteSerpentDEBUG;
        Vector2 originTete, originTeteBounds, tetePos;
        Rectangle boundsSerpent;

        Texture2D corpsSerpent;
        public struct corps
        {
            public Vector2 corpsPos;
            public Vector2 originCorps;
            public float RotationCorps;
            public Rectangle boundsCorps;
        }
        corps[] lesCorps = new corps[(int)Math.Pow(2, 20)];

        Texture2D appatBIT, appatBITDEBUG;
        Vector2 originBIT, BITpos;
        Rectangle BITbounds;
        Random posXBIT, posYBIT;

        SpriteFont debug;

        bool goUp, goDown, goLeft, goRight, gameOver;
        int deux, sizeSerpent, speed, score, oldSizeSerpent;
        float RotationTete;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.IsFullScreen = false;
            graphics.PreferredBackBufferHeight = 720;
            graphics.PreferredBackBufferWidth = 1280;
            graphics.ApplyChanges();

            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            goUp = goDown = goLeft = gameOver = false;
            goRight = true;
            sizeSerpent = oldSizeSerpent = 100;
            speed = 1;
            RotationTete = 0f;
            score = 0;
            posXBIT = new Random();
            posYBIT = new Random();

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            teteSerpent = Content.Load<Texture2D>("teteMAIN");
            teteSerpentDEBUG = Content.Load<Texture2D>("teteDEBUG");
            originTete.X = teteSerpent.Width / 2;
            originTete.Y = teteSerpent.Height / 2;

            corpsSerpent = Content.Load<Texture2D>("corpsMAIN-1x2");

            tetePos = new Vector2(50, (graphics.GraphicsDevice.Viewport.Height / 2));

            for (int cpt = 0; cpt < sizeSerpent; cpt++)
            {
                lesCorps[cpt].corpsPos = new Vector2((tetePos.X - 20) - corpsSerpent.Width * deux, tetePos.Y);
                lesCorps[cpt].originCorps.X = corpsSerpent.Width / 2;
                lesCorps[cpt].originCorps.Y = corpsSerpent.Height / 2;
                deux++;
            }

            appatBIT = Content.Load<Texture2D>("BIT");
            appatBITDEBUG = Content.Load<Texture2D>("BITDEBUG");
            BITpos = new Vector2(posXBIT.Next(50, graphics.GraphicsDevice.Viewport.Width - 20), posYBIT.Next(20, graphics.GraphicsDevice.Viewport.Height - 20));
            originBIT.X = appatBIT.Width / 2;
            originBIT.Y = appatBIT.Height / 2;
            BITbounds = new Rectangle((int)BITpos.X - appatBIT.Width / 2, (int)BITpos.Y - appatBIT.Height / 2, 16, 16);

            boundsSerpent = new Rectangle((int)tetePos.X + teteSerpent.Width / 2, (int)tetePos.Y - teteSerpent.Height / 2, 16, 1);
            originTeteBounds.X = tetePos.X + teteSerpent.Width / 2;
            originTeteBounds.Y = tetePos.Y - teteSerpent.Height / 2;

            background = Content.Load<Texture2D>("grille");
            debug = Content.Load<SpriteFont>("Text");
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            if (!gameOver)
            {
                for (int cpt = 0; cpt < sizeSerpent; cpt++)
                {
                    lesCorps[cpt].boundsCorps = new Rectangle((int)lesCorps[cpt].corpsPos.X, (int)lesCorps[cpt].corpsPos.Y, 1, 2);
                }
                if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Left) && !goRight)
                {
                    goLeft = true;
                    goDown = goUp = goRight = false;
                }
                if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Right) && !goLeft)
                {
                    goRight = true;
                    goDown = goUp = goLeft = false;
                }
                if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Up) && !goDown)
                {
                    goUp = true;
                    goDown = goLeft = goRight = false;
                }
                if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Down) && !goUp)
                {
                    goDown = true;
                    goLeft = goUp = goRight = false;
                }
                if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.V) && sizeSerpent < lesCorps.Length)
                {
                    Grandir();
                }
                if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.B))
                {
                    score++;
                }
                else if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Space) && sizeSerpent > 20)
                {
                    lesCorps[sizeSerpent - 1].corpsPos.X = 0f;
                    lesCorps[sizeSerpent - 1].corpsPos.Y = 0f;
                    sizeSerpent--;
                }
                for (int test = 0; test <= 2; test++)
                {
                    //MOUVEMENT TETE CONTINU VERS LE HAUT
                    if (goUp && !goDown)
                    {
                        tetePos.Y -= speed;
                        RotationTete = -MathHelper.Pi / 2;
                        boundsSerpent = new Rectangle((int)tetePos.X - teteSerpent.Height / 2, (int)tetePos.Y - teteSerpent.Width / 2, 16, 25);
                    }
                    //MOUVEMENT TETE CONTINU VERS LE BAS
                    else if (!goUp && goDown)
                    {
                        tetePos.Y += speed;
                        RotationTete = MathHelper.Pi / 2;
                        boundsSerpent = new Rectangle((int)tetePos.X - teteSerpent.Height / 2, (int)tetePos.Y - teteSerpent.Width / 3, 16, 25);
                    }
                    //MOUVEMENT TETE CONTINU VERS LA GAUCHE
                    if (goLeft && !goRight)
                    {
                        tetePos.X -= speed;
                        RotationTete = MathHelper.Pi;
                        boundsSerpent = new Rectangle((int)tetePos.X - teteSerpent.Width / 2, (int)tetePos.Y - teteSerpent.Height / 2, 25, 16);
                    }
                    //MOUVEMENT TETE CONTINU VERS LA DROITE
                    else if (!goLeft && goRight)
                    {
                        tetePos.X += speed;
                        RotationTete = MathHelper.Pi * 2;
                        boundsSerpent = new Rectangle((int)tetePos.X - teteSerpent.Width / 3, (int)tetePos.Y - teteSerpent.Height / 2, 25, 16);
                    }


                    tirerCorps(0);
                    for (int cpt = 0; cpt < sizeSerpent; cpt++)
                    {
                        if (cpt != lesCorps.Length - 1)
                        {
                            tirerCorps(cpt, cpt + 1);
                        }
                    }
                }

                //GAUCHE ECRAN
                if (tetePos.X - teteSerpent.Width / 2 <= 0 && !goRight && goLeft) goLeft = false;
                //DROITE ECRAN
                if (tetePos.X >= (graphics.GraphicsDevice.Viewport.Width - teteSerpent.Width / 2) && !goLeft && goRight) goRight = false;
                //HAUT ECRAN
                if (tetePos.Y - teteSerpent.Width / 2 <= 0 && goUp && !goDown) goUp = false;
                //BAS ECRAN
                if (tetePos.Y >= (graphics.GraphicsDevice.Viewport.Height - teteSerpent.Width / 2) && goDown && !goUp) goDown = false;

            }

            //COLLISION
            if (!goUp && !goDown && !goLeft && !goRight)
            {
                gameOver = true;
            }
            for (int cpt = 0; cpt < sizeSerpent; cpt++)
            {
                if (boundsSerpent.Intersects(lesCorps[cpt].boundsCorps))
                {
                    gameOver = true;
                }
            }


            if (sizeSerpent < oldSizeSerpent + 40)
            {
                Grandir();
            }
            if (boundsSerpent.Intersects(BITbounds))
            {
                oldSizeSerpent = sizeSerpent;
                score += 10;
                BITpos = new Vector2(posXBIT.Next(50, graphics.GraphicsDevice.Viewport.Width - 20), posYBIT.Next(20, graphics.GraphicsDevice.Viewport.Height - 20));
                originBIT.X = appatBIT.Width / 2;
                originBIT.Y = appatBIT.Height / 2;
                BITbounds = new Rectangle((int)BITpos.X - appatBIT.Width / 2, (int)BITpos.Y - appatBIT.Height / 2, 16, 16);
            }

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            //GraphicsDevice.Clear(Color.CornflowerBlue);

            //BACKGROUND
            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, SamplerState.LinearWrap, DepthStencilState.Default, RasterizerState.CullNone);
            spriteBatch.Draw(background, new Rectangle(0, 0, 1280, 720), new Rectangle(0, 0, 1280, 720), Color.White);
            spriteBatch.End();

            //LAYER 1
            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
            //spriteBatch.Draw(teteSerpent, tetePos, Color.White);
            for (int cpt = 0; cpt < sizeSerpent; cpt++)
            {
                spriteBatch.Draw(corpsSerpent, lesCorps[cpt].corpsPos, null, Color.White, lesCorps[cpt].RotationCorps, lesCorps[cpt].originCorps, 1.0f, SpriteEffects.None, 0f);
                //spriteBatch.Draw(corpsSerpent, lesCorps[cpt].corpsPos, Color.White);
            }
            spriteBatch.Draw(appatBITDEBUG, BITpos, Color.White);
            spriteBatch.End();

            //LAYER 2
            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
            spriteBatch.Draw(appatBIT, BITpos, Color.White);
            spriteBatch.Draw(teteSerpent, tetePos, null, Color.White, RotationTete, originTete, 1.0f, SpriteEffects.None, 0f);
            spriteBatch.Draw(teteSerpentDEBUG, boundsSerpent, Color.White);
            spriteBatch.End();

            //LAYER 3 - TEXT
            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
            if (gameOver)
            {
                spriteBatch.DrawString(debug, "GAME OVER", new Vector2(500, 0), Color.Red);
            }
            spriteBatch.DrawString(debug, sizeSerpent.ToString(), new Vector2(0, 0), Color.Red);
            spriteBatch.DrawString(debug, "DEBUG - corpsJoueur1[" + score.ToString() + "]", new Vector2(50, 0), Color.Red);
            spriteBatch.End();

            base.Draw(gameTime);
        }

        public void tirerCorps(int corpsNPlusUn)
        {
            //DROITE
            if (RotationTete == MathHelper.Pi * 2)
            {
                if (lesCorps[corpsNPlusUn].corpsPos.Y != tetePos.Y)
                {
                    if (lesCorps[corpsNPlusUn].corpsPos.Y < tetePos.Y) lesCorps[corpsNPlusUn].corpsPos.Y += speed;
                    else if (lesCorps[corpsNPlusUn].corpsPos.Y > tetePos.Y) lesCorps[corpsNPlusUn].corpsPos.Y -= speed;
                }
                else
                {
                    lesCorps[corpsNPlusUn].RotationCorps = MathHelper.Pi * 2;
                    lesCorps[corpsNPlusUn].corpsPos.X += speed;
                }
            }
            //GAUCHE
            else if (RotationTete == MathHelper.Pi)
            {
                if (lesCorps[corpsNPlusUn].corpsPos.Y != tetePos.Y)
                {
                    if (lesCorps[corpsNPlusUn].corpsPos.Y < tetePos.Y) lesCorps[corpsNPlusUn].corpsPos.Y += speed;
                    else if (lesCorps[corpsNPlusUn].corpsPos.Y > tetePos.Y) lesCorps[corpsNPlusUn].corpsPos.Y -= speed;
                }
                else
                {
                    lesCorps[corpsNPlusUn].RotationCorps = MathHelper.Pi;
                    lesCorps[corpsNPlusUn].corpsPos.X -= speed;
                }
            }
            //HAUT
            else if (RotationTete == -MathHelper.Pi / 2)
            {
                if (lesCorps[corpsNPlusUn].corpsPos.X != tetePos.X)
                {
                    if (lesCorps[corpsNPlusUn].corpsPos.X > tetePos.X) lesCorps[corpsNPlusUn].corpsPos.X -= speed;
                    else if (lesCorps[corpsNPlusUn].corpsPos.X < tetePos.X) lesCorps[corpsNPlusUn].corpsPos.X += speed;
                }
                else
                {
                    lesCorps[corpsNPlusUn].RotationCorps = -MathHelper.Pi / 2;
                    lesCorps[corpsNPlusUn].corpsPos.Y -= speed;
                }
            }
            //BAS
            else if (RotationTete == MathHelper.Pi / 2)
            {
                if (lesCorps[corpsNPlusUn].corpsPos.X != tetePos.X)
                {
                    if (lesCorps[corpsNPlusUn].corpsPos.X > tetePos.X) lesCorps[corpsNPlusUn].corpsPos.X -= speed;
                    else if (lesCorps[corpsNPlusUn].corpsPos.X < tetePos.X) lesCorps[corpsNPlusUn].corpsPos.X += speed;
                }
                else
                {
                    lesCorps[corpsNPlusUn].RotationCorps = MathHelper.Pi / 2;
                    lesCorps[corpsNPlusUn].corpsPos.Y += speed;
                }
            }
        }

        public void tirerCorps(int corpsN, int corpsNPlusUn)
        {
            //DROITE
            if (lesCorps[corpsN].RotationCorps == MathHelper.Pi * 2)
            {
                if (lesCorps[corpsNPlusUn].corpsPos.Y != lesCorps[corpsN].corpsPos.Y)
                {
                    if (lesCorps[corpsNPlusUn].corpsPos.Y < lesCorps[corpsN].corpsPos.Y) lesCorps[corpsNPlusUn].corpsPos.Y += speed;
                    else if (lesCorps[corpsNPlusUn].corpsPos.Y > lesCorps[corpsN].corpsPos.Y) lesCorps[corpsNPlusUn].corpsPos.Y -= speed;
                }
                else
                {
                    lesCorps[corpsNPlusUn].RotationCorps = MathHelper.Pi * 2;
                    lesCorps[corpsNPlusUn].corpsPos.X += speed;
                }
            }
            //GAUCHE
            else if (lesCorps[corpsN].RotationCorps == MathHelper.Pi)
            {
                if (lesCorps[corpsNPlusUn].corpsPos.Y != lesCorps[corpsN].corpsPos.Y)
                {
                    if (lesCorps[corpsNPlusUn].corpsPos.Y < lesCorps[corpsN].corpsPos.Y) lesCorps[corpsNPlusUn].corpsPos.Y += speed;
                    else if (lesCorps[corpsNPlusUn].corpsPos.Y > lesCorps[corpsN].corpsPos.Y) lesCorps[corpsNPlusUn].corpsPos.Y -= speed;
                }
                else
                {
                    lesCorps[corpsNPlusUn].RotationCorps = MathHelper.Pi;
                    lesCorps[corpsNPlusUn].corpsPos.X -= speed;
                }
            }
            //HAUT
            else if (lesCorps[corpsN].RotationCorps == -MathHelper.Pi / 2)
            {
                if (lesCorps[corpsNPlusUn].corpsPos.X != lesCorps[corpsN].corpsPos.X)
                {
                    if (lesCorps[corpsNPlusUn].corpsPos.X > lesCorps[corpsN].corpsPos.X) lesCorps[corpsNPlusUn].corpsPos.X -= speed;
                    else if (lesCorps[corpsNPlusUn].corpsPos.X < lesCorps[corpsN].corpsPos.X) lesCorps[corpsNPlusUn].corpsPos.X += speed;
                }
                else
                {
                    lesCorps[corpsNPlusUn].RotationCorps = -MathHelper.Pi / 2;
                    lesCorps[corpsNPlusUn].corpsPos.Y -= speed;
                }
            }
            //BAS
            else if (lesCorps[corpsN].RotationCorps == MathHelper.Pi / 2)
            {
                if (lesCorps[corpsNPlusUn].corpsPos.X != lesCorps[corpsN].corpsPos.X)
                {
                    if (lesCorps[corpsNPlusUn].corpsPos.X > lesCorps[corpsN].corpsPos.X) lesCorps[corpsNPlusUn].corpsPos.X -= speed;
                    else if (lesCorps[corpsNPlusUn].corpsPos.X < lesCorps[corpsN].corpsPos.X) lesCorps[corpsNPlusUn].corpsPos.X += speed;
                }
                else
                {
                    lesCorps[corpsNPlusUn].RotationCorps = MathHelper.Pi / 2;
                    lesCorps[corpsNPlusUn].corpsPos.Y += speed;
                }
            }
        }

        public void Grandir()
        {
            //DROITE
            if (lesCorps[sizeSerpent - 1].RotationCorps == MathHelper.Pi * 2)
            {
                lesCorps[sizeSerpent].corpsPos = new Vector2(lesCorps[sizeSerpent - 1].corpsPos.X - corpsSerpent.Width, lesCorps[sizeSerpent - 1].corpsPos.Y);
                lesCorps[sizeSerpent].RotationCorps = MathHelper.Pi * 2;
            }
            //GAUCHE
            else if (lesCorps[sizeSerpent - 1].RotationCorps == MathHelper.Pi)
            {
                lesCorps[sizeSerpent].corpsPos = new Vector2(lesCorps[sizeSerpent - 1].corpsPos.X + corpsSerpent.Width, lesCorps[sizeSerpent - 1].corpsPos.Y);
                lesCorps[sizeSerpent].RotationCorps = MathHelper.Pi;
            }
            //HAUT
            else if (lesCorps[sizeSerpent - 1].RotationCorps == -MathHelper.Pi / 2)
            {
                lesCorps[sizeSerpent].corpsPos = new Vector2(lesCorps[sizeSerpent - 1].corpsPos.X, lesCorps[sizeSerpent - 1].corpsPos.Y + corpsSerpent.Width);
                lesCorps[sizeSerpent].RotationCorps = -MathHelper.Pi / 2;
            }
            //BAS
            else if (lesCorps[sizeSerpent - 1].RotationCorps == MathHelper.Pi / 2)
            {
                lesCorps[sizeSerpent].corpsPos = new Vector2(lesCorps[sizeSerpent - 1].corpsPos.X, lesCorps[sizeSerpent - 1].corpsPos.Y - corpsSerpent.Width);
                lesCorps[sizeSerpent].RotationCorps = MathHelper.Pi / 2;
            }
            lesCorps[sizeSerpent].originCorps.X = lesCorps[sizeSerpent - 1].originCorps.X;
            lesCorps[sizeSerpent].originCorps.Y = lesCorps[sizeSerpent - 1].originCorps.Y;
            sizeSerpent++;
            Console.WriteLine(sizeSerpent);
        }
    }
}
